/*
 *  Created on: May 10, 2009
 *      Author: Ramesh Rajaby
 */


#include "ParsingUtils.h"


namespace SymphonyAST {


bool isValidInWord(char c) {
	return isalnum(c) || (c == '_');
}

string getNextWord(const string& s, int& start) {
	while (!isValidInWord(s[start]) && start < (int)s.length())
		start++;

	for (int i = start; i < (int)s.length(); i++)
		if (!isValidInWord(s[i])) {
			int temp = start;
			start = i;

			string word = substring(s, temp, i);
			trim(word);
			return word;
		}

	int temp = start;
	start = s.length();

	string word = substring(s, temp, s.length());
	trim(word);
	return word;
}


string getFirstWord(const string& s) {
	int i = 0;
	return getNextWord(s, i);
}


string substring(const string& str, int start, int end) {
	return str.substr(start, end-start);
}


bool isValidWord(string& word) {
	int len = word.length();
	for (int i = 0; i < len; i++)
		if (!isValidInWord(word[i]))
			return false;
	return true;
}


int lookForOpeningRoundBracket(string& s, int start) {
	int open = 0;

	int i;
	for (i = start-1; i >= 0; i--) {
		open += (s[i] == '(');
		open -= (s[i] == ')');

		if (open > 0)
			break;
	}

	return i;
}

int lookForOpeningSquareBracket(string& s, int start) {
	int open = 0;

	int i;
	for (i = start-1; i >= 0; i--) {
		open += (s[i] == '[');
		open -= (s[i] == ']');

		if (open > 0)
			break;
	}

	return i;
}


int lookForClosingRoundBracket(string& s, int start) {
	int open = 0;

	int i, len = s.length();
	for (i = start+1; i < len; i++) {
		open += (s[i] == '(');
		open -= (s[i] == ')');

		if (open < 0)
			break;
	}

	return i;
}

int lookForClosingSquareBracket(string& s, int start) {
	int open = 0;

	int i, len = s.length();
	for (i = start+1; i < len; i++) {
		open += (s[i] == '[');
		open -= (s[i] == ']');

		if (open < 0)
			break;
	}

	return i;
}


string getNextParameter(string& s, int& start) {
	for (int i = start; i < (int)s.length(); i++) {
		if (s[i] == '(') {
			i = lookForClosingRoundBracket(s, i);
		} else if (s[i] == ',' || s[i] == ')') {
			int temp = start;
			start = i;

			string word = substring(s, temp, i);
			trim(word);
			return word;
		}
	}
	int temp = start;
	start = s.length();

	string word = substring(s, temp, start);
	trim(word);
	return word;
}


int findExcludingBracketsAndConsts(string& s, const string& toFind, int start) {
	int toFindLen = toFind.length();
	int len = s.length();

	if (toFindLen > len)
		return len;
	else if (toFindLen == 0)
		return start;

	for (int i = start; i <= len-toFindLen; i++) {
		if (s[i] == '(') {
			i = lookForClosingRoundBracket(s, i);
		} else if (s[i] == '[') {
			i = lookForClosingSquareBracket(s, i);
		} else if (s[i] == '\'' || s[i] == '"') {
			do {
				i = s.find(s[i], i+1);
			} while (i-1 > 0 && s[i-1] == '\\');
		} else {
			int j = 0;
			while (j < toFindLen && s[i+j] == toFind[j])
				j++;
			if (j == toFindLen)
				return i;
		}
	}

	return len;
}


int rfindExcludingBracketsAndConsts(string& s, const string& toFind, int start) {
	int toFindLen = toFind.length();
	int len = s.length();

	if (toFindLen > len)
		return -1;
	else if (toFindLen == 0)
		return start;

	start = min(start, len-1);
	for (int i = start; i >= toFindLen-1; i--) {
		if (s[i] == ')') {
			i = lookForOpeningRoundBracket(s, i);
		} else if (s[i] == ']') {
			i = lookForOpeningSquareBracket(s, i);
		} else if (s[i] == '\'' || s[i] == '"') {
			do {
				i = s.rfind(s[i], i+1);
			} while (i-1 > 0 && s[i-1] == '\\');
		}
		else {
			int j = 0;
			while (j >= 0 && s[i-j] == toFind[toFindLen-1-j])
				j++;
			if (j == toFindLen)
				return i;
		}
	}

	return -1;
}


char rgetNextNonWhiteChar(string& exp, int start) {
	for (int i = start; i >= 0; i--) {
		if (exp[i] != ' ' || exp[i] != '\t')
			return exp[i];
	}

	return ' ';
}


bool startsWith(const string& s, const string& start) {
	if (s.length() < start.length())
		return false;

	int len = start.length();
	for (int i = 0; i < len; i++)
		if (s[i] != start[i])
			return false;

	return true;
}


bool isAssignmentOp(string op) {
	trim(op);
	return (op == "=" || op == "+=" || op == "-=" || op == "*=" || op == "/=" || op == "%=");
}


void checkLValue(string lvalue) {
	regex e("[a-zA-Z_][\\w]*");

	if (!regex_match(lvalue, e)) {
		throw "Invalid assignment lvalue: " + lvalue;
	}
}

}
